#pragma once

//
// kernel based on OpenCLIPP library
// https://github.com/CRVI/OpenCLIPP
//

// names of kernel entry points
static const std::vector<std::string> entries = { "resize_nn", "resize_linear", "resize_bicubic" };

// kernel with 4 resize methods
static const std::string resizeKernel =

"__constant sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST;\n"
"\n"
"//#pragma OPENCL EXTENSION cl_amd_printf : enable\n"
"//int printf(const char *restrict format, ...);\n"
"\n"
"struct CLImage\n"
"{\n"
"   uint Width;\n"
"   uint Height;\n"
"};\n"
"\n"
"//  nearest neighbour interpolation resizing\n"
"// ----------------------------------------------------------------------------------\n"
"//\n"
"__kernel void resize_nn(__read_only image2d_t source, __write_only image2d_t dest, struct CLImage src_img, struct CLImage dst_img, float ratioX, float ratioY)\n"
"{\n"
"   const int gx = get_global_id(0);\n"
"   const int gy = get_global_id(1);\n"
"   const int2 pos = { gx, gy };\n"
"\n"
"   if (pos.x >= dst_img.Width || pos.y >= dst_img.Height)\n"
"      return;\n"
"\n"
"   float2 srcpos = {(pos.x + 0.4995f) / ratioX, (pos.y + 0.4995f) / ratioY};\n"
"   int2 SrcSize = (int2)(src_img.Width, src_img.Height);\n"
"\n"
"   float4 value;\n"
"\n"
"   int2 ipos = convert_int2(srcpos);\n"
"   if (ipos.x < 0 || ipos.x >= SrcSize.x || ipos.y < 0 || ipos.y >= SrcSize.y)\n"
"      value = 0;\n"
"   else\n"
"      value = read_imagef(source, sampler, ipos);\n"
"\n"
"   write_imagef(dest, pos, value);\n"
"}\n"
"\n"
"//  linear interpolation resizing\n"
"// ----------------------------------------------------------------------------------\n"
"//\n"
"__kernel void resize_linear(__read_only image2d_t source, __write_only image2d_t dest, struct CLImage src_img, struct CLImage dst_img, float ratioX, float ratioY)\n"
"{\n"
"   const int gx = get_global_id(0);\n"
"   const int gy = get_global_id(1);\n"
"   const int2 pos = { gx, gy };\n"
"\n"
"   if (pos.x >= dst_img.Width || pos.y >= dst_img.Height)\n"
"      return;\n"
"\n"
"   float2 srcpos = {(pos.x + 0.4995f) / ratioX, (pos.y + 0.4995f) / ratioY};\n"
"   int2 SrcSize = { (int)src_img.Width, (int)src_img.Height };\n"
"\n"
"   float4 value;\n"
"\n"
"   if ((int)(srcpos.x + .5f) == SrcSize.x)\n"
"      srcpos.x = SrcSize.x - 0.5001f;\n"
"\n"
"   if ((int)(srcpos.y + .5f) == SrcSize.y)\n"
"      srcpos.y = SrcSize.y - 0.5001f;\n"
"\n"
"   srcpos -= (float2)(0.5f, 0.5f);\n"
"\n"
"   if (srcpos.x < -0.5f || srcpos.x >= SrcSize.x - 1 || srcpos.y < -0.5f || srcpos.y >= SrcSize.y - 1)\n"
"      value = 0;\n"
"\n"
"   int x1 = (int)(srcpos.x);\n"
"   int x2 = (int)(srcpos.x + 1);\n"
"   int y1 = (int)(srcpos.y);\n"
"   int y2 = (int)(srcpos.y + 1);\n"
"\n"
"   float factorx1 = 1 - (srcpos.x - x1);\n"
"   float factorx2 = 1 - factorx1;\n"
"   float factory1 = 1 - (srcpos.y - y1);\n"
"   float factory2 = 1 - factory1;\n"
"\n"
"   float4 f1 = factorx1 * factory1;\n"
"   float4 f2 = factorx2 * factory1;\n"
"   float4 f3 = factorx1 * factory2;\n"
"   float4 f4 = factorx2 * factory2;\n"
"\n"
"   const int2 pos0 = { x1, y1 };\n"
"   const int2 pos1 = { x2, y1 };\n"
"   const int2 pos2 = { x1, y2 };\n"
"   const int2 pos3 = { x2, y2 };\n"
"\n"
"   float4 v1 = read_imagef(source, sampler, pos0);\n"
"   float4 v2 = read_imagef(source, sampler, pos1);\n"
"   float4 v3 = read_imagef(source, sampler, pos2);\n"
"   float4 v4 = read_imagef(source, sampler, pos3);\n"
"   value =  v1 * f1 + v2 * f2 + v3 * f3 + v4 * f4;\n"
"\n"
"   write_imagef(dest, pos, value);\n"
"}\n"
"\n"
"\n"
"//  bicubic interpolation resizing\n"
"// ----------------------------------------------------------------------------------\n"
"//\n"
"float4 sample_bicubic_border(__read_only image2d_t source, float2 pos, int2 SrcSize)\n"
"{\n"
"   int2 isrcpos = convert_int2(pos);\n"
"   float dx = pos.x - isrcpos.x;\n"
"   float dy = pos.y - isrcpos.y;\n"
"\n"
"   float4 C[4] = {0, 0, 0, 0};\n"
"\n"
"   if (isrcpos.x < 0 || isrcpos.x >= SrcSize.x)\n"
"      return 0;\n"
"\n"
"   if (isrcpos.y < 0 || isrcpos.y >= SrcSize.y)\n"
"      return 0;\n"
"\n"
"   for (int i = 0; i < 4; i++)\n"
"   {\n"
"      int y = isrcpos.y - 1 + i;\n"
"      if (y < 0)\n"
"         y = 0;\n"
"\n"
"      if (y >= SrcSize.y)\n"
"         y = SrcSize.y - 1;\n"
"\n"
"      int Middle = clamp(isrcpos.x, 0, SrcSize.x - 1);\n"
"\n"
"      const int2 pos0 = { Middle, y };\n"
"      float4 center = read_imagef(source, sampler, pos0);\n"
"\n"
"      float4 left = 0, right1 = 0, right2 = 0;\n"
"      if (isrcpos.x - 1 >= 0)\n"
"      {\n"
"         const int2 pos1 = { isrcpos.x - 1, y };\n"
"         left = read_imagef(source, sampler, pos1);\n"
"      }\n"
"      else\n"
"      {\n"
"         left = center;\n"
"      }\n"
"\n"
"      if (isrcpos.x + 1 < SrcSize.x)\n"
"      {\n"
"         const int2 pos2 = { isrcpos.x + 1, y };\n"
"         right1 = read_imagef(source, sampler, pos2);\n"
"      }\n"
"      else\n"
"      {\n"
"         right1 = center;\n"
"      }\n"
"\n"
"      if (isrcpos.x + 2 < SrcSize.x)\n"
"      {\n"
"         const int2 pos3 = { isrcpos.x + 2, y };\n"
"         right2 = read_imagef(source, sampler, pos3);\n"
"      }\n"
"      else\n"
"      {\n"
"         right2 = right1;\n"
"      }\n"
"\n"
"      float4 a0 = center;\n"
"      float4 d0 = left - a0;\n"
"      float4 d2 = right1 - a0;\n"
"      float4 d3 = right2 - a0;\n"
"\n"
"      float4 a1 = -1.0f / 3 * d0 + d2 - 1.0f / 6 * d3;\n"
"      float4 a2 =  1.0f / 2 * d0 + 1.0f / 2 * d2;\n"
"      float4 a3 = -1.0f / 6 * d0 - 1.0f / 2 * d2 + 1.0f / 6 * d3;\n"
"      C[i] = a0 + a1 * dx + a2 * dx * dx + a3 * dx * dx * dx;\n"
"   }\n"
"\n"
"   float4 d0 = C[0] - C[1];\n"
"   float4 d2 = C[2] - C[1];\n"
"   float4 d3 = C[3] - C[1];\n"
"   float4 a0 = C[1];\n"
"   float4 a1 = -1.0f / 3 * d0 + d2 -1.0f / 6 * d3;\n"
"   float4 a2 = 1.0f / 2 * d0 + 1.0f / 2 * d2;\n"
"   float4 a3 = -1.0f / 6 * d0 - 1.0f / 2 * d2 + 1.0f / 6 * d3;\n"
"\n"
"   return a0 + a1 * dy + a2 * dy * dy + a3 * dy * dy * dy;\n"
"}\n"
"\n"
"__kernel void resize_bicubic(__read_only image2d_t source, __write_only image2d_t dest, struct CLImage src_img, struct CLImage dst_img, float ratioX, float ratioY)\n"
"{\n"
"   const int gx = get_global_id(0);\n"
"   const int gy = get_global_id(1);\n"
"   const int2 pos = { gx, gy };\n"
"\n"
"   if (pos.x >= dst_img.Width || pos.y >= dst_img.Height)\n"
"      return;\n"
"\n"
"   float2 srcpos = {(pos.x + 0.4995f) / ratioX, (pos.y + 0.4995f) / ratioY};\n"
"   int2 SrcSize = { (int)src_img.Width, (int)src_img.Height };\n"
"\n"
"   float4 value;\n"
"\n"
"   srcpos -= (float2)(0.5f, 0.5f);\n"
"\n"
"   int2 isrcpos = convert_int2(srcpos);\n"
"   float dx = srcpos.x - isrcpos.x;\n"
"   float dy = srcpos.y - isrcpos.y;\n"
"\n"
"   if (isrcpos.x <= 0 || isrcpos.x >= SrcSize.x - 2)\n"
"      value = sample_bicubic_border(source, srcpos, SrcSize);\n"
"\n"
"   if (isrcpos.y <= 0 || isrcpos.y >= SrcSize.y - 2)\n"
"      value = sample_bicubic_border(source, srcpos, SrcSize);\n"
"\n"
"   float4 C[4] = {0, 0, 0, 0};\n"
"\n"
"   for (int i = 0; i < 4; i++)\n"
"   {\n"
"      const int y = isrcpos.y - 1 + i;\n"
"\n"
"      const int2 pos0 = { isrcpos.x, y };\n"
"      const int2 pos1 = { isrcpos.x - 1, y };\n"
"      const int2 pos2 = { isrcpos.x + 1, y };\n"
"      const int2 pos3 = { isrcpos.x + 2, y };\n"
"\n"
"      float4 a0 = read_imagef(source, sampler, pos0);\n"
"      float4 d0 = read_imagef(source, sampler, pos1) - a0;\n"
"      float4 d2 = read_imagef(source, sampler, pos2) - a0;\n"
"      float4 d3 = read_imagef(source, sampler, pos3) - a0;\n"
"\n"
"      float4 a1 = -1.0f / 3 * d0 + d2 - 1.0f / 6 * d3;\n"
"      float4 a2 =  1.0f / 2 * d0 + 1.0f / 2 * d2;\n"
"      float4 a3 = -1.0f / 6 * d0 - 1.0f / 2 * d2 + 1.0f / 6 * d3;\n"
"      C[i] = a0 + a1 * dx + a2 * dx * dx + a3 * dx * dx * dx;\n"
"   }\n"
"\n"
"   float4 d0 = C[0] - C[1];\n"
"   float4 d2 = C[2] - C[1];\n"
"   float4 d3 = C[3] - C[1];\n"
"   float4 a0 = C[1];\n"
"   float4 a1 = -1.0f / 3 * d0 + d2 -1.0f / 6 * d3;\n"
"   float4 a2 = 1.0f / 2 * d0 + 1.0f / 2 * d2;\n"
"   float4 a3 = -1.0f / 6 * d0 - 1.0f / 2 * d2 + 1.0f / 6 * d3;\n"
"   value = a0 + a1 * dy + a2 * dy * dy + a3 * dy * dy * dy;\n"
"\n"
"   write_imagef(dest, pos, value);\n"
"}\n"
"\n"
"\n";
